#include "bsp.h"

static const struct {
    GPIO_TypeDef *gpio;
    uint16_t      pin;
} l_bspLedConfig[BSP_LED_MAX] = {
    [0] = { .gpio = GPIOG, .pin = GPIO_PIN_11 },
    [1] = { .gpio = GPIOG, .pin = GPIO_PIN_15 },
};

static UART_HandleTypeDef l_huart6;

void Error_Handler(void)
{
    __disable_irq();
    while (1U) {
    }
}

#if defined (USE_FULL_ASSERT)
void assert_failed(uint8_t *file, uint32_t line)
{
    (void)file;
    (void)line;
}
#endif // defined (USE_FULL_ASSERT)


void SysTick_Handler(void)
{
    HAL_IncTick();
}

void BSP_init(void)
{
    // hal driver initial
    HAL_Init();

    // system clock configuration
    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState       = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource  = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM       = 4;
    RCC_OscInitStruct.PLL.PLLN       = 168;
    RCC_OscInitStruct.PLL.PLLP       = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ       = 4;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    RCC_ClkInitStruct.ClockType      = RCC_CLOCKTYPE_HCLK |
        RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
        Error_Handler();
    }

    // led configuration
    __HAL_RCC_GPIOG_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {
        .Mode  = GPIO_MODE_OUTPUT_PP,
        .Pull  = GPIO_PULLUP,
        .Speed = GPIO_SPEED_FREQ_LOW,
    };

    for (int i = 0; i < (int)BSP_LED_MAX; ++i) {
        GPIO_InitStruct.Pin = l_bspLedConfig[i].pin;
        HAL_GPIO_Init(l_bspLedConfig[i].gpio, &GPIO_InitStruct);
        HAL_GPIO_WritePin(l_bspLedConfig[i].gpio, l_bspLedConfig[i].pin,
            (GPIO_PinState)BSP_LED_OFF);
    }

    // debug uart configuration
    l_huart6.Instance          = USART6;
    l_huart6.Init.BaudRate     = 115200;
    l_huart6.Init.WordLength   = UART_WORDLENGTH_8B;
    l_huart6.Init.StopBits     = UART_STOPBITS_1;
    l_huart6.Init.Parity       = UART_PARITY_NONE;
    l_huart6.Init.Mode         = UART_MODE_TX_RX;
    l_huart6.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    l_huart6.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&l_huart6) != HAL_OK) {
        Error_Handler();
    }
}

void BSP_delay(uint32_t ticks)
{
    HAL_Delay(ticks);
}

void BSP_ledCtrl(BSP_LedId id, BSP_LedState state)
{
    HAL_GPIO_WritePin(l_bspLedConfig[id].gpio, l_bspLedConfig[id].pin,
        (GPIO_PinState)state);
}

int _write(int fd, char *ptr, int len)
{
    (void)fd;
    HAL_UART_Transmit(&l_huart6, (uint8_t *)ptr, len, 0xFFFF);
    return len;
}

int _read(int fd, char *ptr, int len)
{
    (void)fd;
    (void)ptr;
    return len;
}
